﻿using System;
using System.Buffers;
using System.Runtime.CompilerServices;


namespace Letter.IO.Binary;

public static class FixedReadExtensions
{
    private static BinaryOrderOperationLE LE
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        get { return BinaryOrderOperationLE.Instance; }
    }
    private static BinaryOrderOperationBE BE
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        get { return BinaryOrderOperationBE.Instance; }
    }

    
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static bool FReadBoolean(in this ReadOnlySequence<byte> buf)
    {
        return FReadUInt8(buf) > 0;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static bool FReadBoolean(in this ReadOnlySpan<byte> buf)
    {
        return FReadUInt8(buf) > 0;
    }



    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static char FReadChar(in this ReadOnlySequence<byte> buf) => FReadCharBE(buf);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static char FReadChar(in this ReadOnlySpan<byte> buf) => FReadCharBE(buf);
    
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static char FReadCharLE(in this ReadOnlySequence<byte> buf) => InternalFReadChar(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static char FReadCharBE(in this ReadOnlySequence<byte> buf) => InternalFReadChar(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static char FReadCharLE(in this ReadOnlySpan<byte> buf) => InternalFReadChar(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static char FReadCharBE(in this ReadOnlySpan<byte> buf) => InternalFReadChar(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static char InternalFReadChar<TOperation>(in ReadOnlySequence<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        int length = sizeof(char);
        if (buf.First.Length >= length)
        {
            return InternalFReadChar(buf.First.Span, operation);
        }
        else
        {
            Span<byte> local = stackalloc byte[length];
            buf.CopyTo(local);
            return InternalFReadChar(local, operation);
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static char InternalFReadChar<TOperation>(in ReadOnlySpan<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        return operation.ReadChar(buf);
    }


    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static sbyte FReadInt8(in this ReadOnlySequence<byte> buf)
    {
        return (sbyte) buf.FReadUInt8();
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static sbyte FReadInt8(in this ReadOnlySpan<byte> buf)
    {
        return (sbyte) buf.FReadUInt8();
    }
    
    
    
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static byte FReadUInt8(in this ReadOnlySequence<byte> buf)
    {
        return FReadUInt8(buf.First.Span);
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static byte FReadUInt8(in this ReadOnlySpan<byte> buf)
    {
        return buf[0];
    }

    

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static short FReadInt16LE(in this ReadOnlySequence<byte> buf) => InternalFReadInt16(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static short FReadInt16BE(in this ReadOnlySequence<byte> buf) => InternalFReadInt16(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static short FReadInt16LE(in this ReadOnlySpan<byte> buf) => InternalFReadInt16(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static short FReadInt16BE(in this ReadOnlySpan<byte> buf) => InternalFReadInt16(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static short InternalFReadInt16<TOperation>(in ReadOnlySequence<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        int size = sizeof(short);
        if (buf.First.Length >= size)
        {
            return InternalFReadInt16(buf.First.Span, operation);
        }
        else
        {
            Span<byte> local = stackalloc byte[size];
            buf.CopyTo(local);
            return InternalFReadInt16(local, operation);
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static short InternalFReadInt16<TOperation>(in ReadOnlySpan<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        return operation.ReadInt16(buf);
    }
    
    
    

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ushort FReadUInt16LE(in this ReadOnlySequence<byte> buf) => InternalFReadUInt16(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ushort FReadUInt16BE(in this ReadOnlySequence<byte> buf) => InternalFReadUInt16(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ushort FReadUInt16LE(in this ReadOnlySpan<byte> buf) => InternalFReadUInt16(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ushort FReadUInt16BE(in this ReadOnlySpan<byte> buf) => InternalFReadUInt16(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static ushort InternalFReadUInt16<TOperation>(in this ReadOnlySequence<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        int size = sizeof(ushort);
        if (buf.First.Length >= size)
        {
            return InternalFReadUInt16(buf.First.Span, operation);
        }
        else
        {
            Span<byte> local = stackalloc byte[size];
            buf.CopyTo(local);
            return InternalFReadUInt16(local, operation);
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static ushort InternalFReadUInt16<TOperation>(in ReadOnlySpan<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        return operation.ReadUInt16(buf);
    }
    
    

    
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int FReadInt32LE(in this ReadOnlySequence<byte> buf) => InternalFReadInt32(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int FReadInt32BE(in this ReadOnlySequence<byte> buf) => InternalFReadInt32(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int FReadInt32LE(in this ReadOnlySpan<byte> buf) => InternalFReadInt32(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int FReadInt32BE(in this ReadOnlySpan<byte> buf) => InternalFReadInt32(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static int InternalFReadInt32<TOperation>(in this ReadOnlySequence<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        int size = sizeof(int);
        if (buf.First.Length >= size)
        {
            return InternalFReadInt32(buf.First.Span, operation);
        }
        else
        {
            Span<byte> local = stackalloc byte[size];
            buf.CopyTo(local);
            return InternalFReadInt32(local, operation);
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static int InternalFReadInt32<TOperation>(in this ReadOnlySpan<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        return operation.ReadInt32(buf);
    }



    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static uint FReadUInt32LE(in this ReadOnlySequence<byte> buf) => InternalFReadUInt32(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static uint FReadUInt32BE(in this ReadOnlySequence<byte> buf) => InternalFReadUInt32(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static uint FReadUInt32LE(in this ReadOnlySpan<byte> buf) => InternalFReadUInt32(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static uint FReadUInt32BE(in this ReadOnlySpan<byte> buf) => InternalFReadUInt32(buf, BE);
    
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static uint InternalFReadUInt32<TOperation>(in this ReadOnlySequence<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        int size = sizeof(uint);
        if (buf.First.Length >= size)
        {
            return InternalFReadUInt32(buf.First.Span, operation);
        }
        else
        {
            Span<byte> local = stackalloc byte[size];
            buf.CopyTo(local);
            return InternalFReadUInt32(local, operation);
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static uint InternalFReadUInt32<TOperation>(in this ReadOnlySpan<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        return operation.ReadUInt32(buf);
    }

    
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static long FReadInt64LE(in this ReadOnlySequence<byte> buf) => InternalFReadInt64(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static long FReadInt64BE(in this ReadOnlySequence<byte> buf) => InternalFReadInt64(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static long FReadInt64LE(in this ReadOnlySpan<byte> buf) => InternalFReadInt64(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static long FReadInt64BE(in this ReadOnlySpan<byte> buf) => InternalFReadInt64(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static long InternalFReadInt64<TOperation>(in this ReadOnlySequence<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        int size = sizeof(long);
        if (buf.First.Length >= size)
        {
            return InternalFReadInt64(buf.First.Span, operation);
        }
        else
        {
            Span<byte> local = stackalloc byte[size];
            buf.CopyTo(local);
            return InternalFReadInt64(local, operation);
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static long InternalFReadInt64<TOperation>(in this ReadOnlySpan<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        return operation.ReadInt64(buf);
    }




    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ulong FReadUInt64LE(in this ReadOnlySequence<byte> buf) => InternalFReadUInt64(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ulong FReadUInt64BE(in this ReadOnlySequence<byte> buf) => InternalFReadUInt64(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ulong FReadUInt64LE(in this ReadOnlySpan<byte> buf) => InternalFReadUInt64(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ulong FReadUInt64BE(in this ReadOnlySpan<byte> buf) => InternalFReadUInt64(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static ulong InternalFReadUInt64<TOperation>(in this ReadOnlySequence<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        int size = sizeof(ulong);
        if (buf.First.Length >= size)
        {
            return InternalFReadUInt64(buf.First.Span, operation);
        }
        else
        {
            Span<byte> local = stackalloc byte[size];
            buf.CopyTo(local);
            return InternalFReadUInt64(local, operation);
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static ulong InternalFReadUInt64<TOperation>(in this ReadOnlySpan<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        return operation.ReadUInt64(buf);
    }
    
    


    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static float FReadFloat32LE(in this ReadOnlySequence<byte> buf) => InternalFReadFloat32(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static float FReadFloat32BE(in this ReadOnlySequence<byte> buf) => InternalFReadFloat32(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static float FReadFloat32LE(in this ReadOnlySpan<byte> buf) => InternalFReadFloat32(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static float FReadFloat32BE(in this ReadOnlySpan<byte> buf) => InternalFReadFloat32(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static float InternalFReadFloat32<TOperation>(in this ReadOnlySequence<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        int size = sizeof(float);
        if (buf.First.Length >= size)
        {
            return InternalFReadFloat32(buf.First.Span, operation);
        }
        else
        {
            Span<byte> local = stackalloc byte[size];
            buf.CopyTo(local);
            return InternalFReadFloat32(local, operation);
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static float InternalFReadFloat32<TOperation>(in this ReadOnlySpan<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        return operation.ReadFloat32(buf);
    }
    
    
    

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static double FReadFloat64LE(in this ReadOnlySequence<byte> buf) => InternalFReadFloat64(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static double FReadFloat64BE(in this ReadOnlySequence<byte> buf) => InternalFReadFloat64(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static double FReadFloat64LE(in this ReadOnlySpan<byte> buf) => InternalFReadFloat64(buf, LE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static double FReadFloat64BE(in this ReadOnlySpan<byte> buf) => InternalFReadFloat64(buf, BE);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static double InternalFReadFloat64<TOperation>(in this ReadOnlySequence<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        int size = sizeof(double);
        if (buf.First.Length >= size)
        {
            return InternalFReadFloat64(buf.First.Span, operation);
        }
        else
        {
            Span<byte> local = stackalloc byte[size];
            buf.CopyTo(local);
            return InternalFReadFloat64(local, operation);
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static double InternalFReadFloat64<TOperation>(in this ReadOnlySpan<byte> buf, TOperation operation)
        where TOperation : IBinaryOrderOperation
    {
        return operation.ReadFloat64(buf);
    }
}